/**
 * Project: apollo-base-dal
 * 
 * File Created at 2016年5月5日
 * 
 * Copyright 2015-2016 dx.com Croporation Limited.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * DongXue software Company. ("Confidential Information").  You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with dx.com.
 */
package com.dx.pf.dal.jdbc.mapper;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.jdbc.core.StatementCreatorUtils;
import org.springframework.jdbc.core.namedparam.AbstractSqlParameterSource;

import com.dx.pf.dal.Logger;
import com.dx.pf.dal.cache.DalCache;
import com.dx.pf.dal.cache.EntryInfo;
import com.dx.pf.dal.constants.DalConstant;
import com.google.common.collect.BiMap;

/** 
* @ClassName: BeanPropertyAccessBeanMapper 
* @Description:使用spring自带的bean属性处理工程获取beanwrapper包装器来解析bean实体对象到map中
* @author wuzhenfang(wzfbj2008@163.com)
* @date 2016年5月5日 上午10:09:46 
* @version V1.0 
*/
public class BeanPropertyAccessBeanMapper extends AbstractSqlParameterSource implements BeanMapper{
	
	private final static Logger logger = Logger.getLogger(BeanPropertyAccessBeanMapper.class);

	private final Map<String, Object> columnValueMap = new HashMap<String, Object>();
	
	private BeanWrapper beanWrapper = null;
	
	private EntryInfo entryInfo = null;
	
	private BiMap<String, String> field2ColName;
	
	//insert into table1(field1,field2) values(value1,value2)
	//update table1 set field1=value1 where 范围
	public boolean flag = false;//拼接字符的标识
	public StringBuilder iColumnListStr = new StringBuilder();//在组装insert字段列表
	public StringBuilder placeholderListStr = new StringBuilder();//占位符列表，在使用insert时候占位符
	
	public StringBuilder uColumnPlaceholderList = new StringBuilder();//在update时的字段=值列表
	
	public StringBuilder iNamedParameterListStr = new StringBuilder();//使用名称占位符列表，在使用insert时候占位符
	public StringBuilder uNamedParameterListStr = new StringBuilder();//使用名称占位符列表，在使用update时候占位符
	public List<Object> valueList = new ArrayList<Object>();//值列表
	
	public BeanPropertyAccessBeanMapper(){
		
	}
	
	public BeanPropertyAccessBeanMapper(Object object){
		if (null == object) {
			logger.error("传入的对象为null。", new NullPointerException());
			throw new NullPointerException("传入的对象为null。");
		}
		this.init(object);
	}
	
	
	public BeanPropertyAccessBeanMapper setBean(Object object) {
		if (null == object) {
			logger.error("传入的对象为null。", new NullPointerException());
			throw new NullPointerException("传入的对象为null。");
		}
		this.init(object);
		return this;
	}
	
	private void init(Object object) {
		this.beanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(object);
		this.entryInfo = DalCache.getInstance().getEntryPropertyMap(object.getClass());
		this.field2ColName = entryInfo.getField2ColName();
		if (null != beanWrapper) {
			//开始解析beanWapper
			for (Iterator<Entry<String, String>> iter = field2ColName.entrySet().iterator(); iter.hasNext();) {
				Entry<String, String> entry = iter.next();
				String fieldName = entry.getKey();
				String columnName = entry.getValue();
				Object value = beanWrapper.getPropertyValue(fieldName);
				if(null != value){
					Class<?> propertyType = beanWrapper.getPropertyType(fieldName);
					super.registerTypeName(columnName, propertyType.getName());
					super.registerSqlType(columnName, StatementCreatorUtils.javaTypeToSqlParameterType(propertyType));
					columnValueMap.put(columnName, value);
					valueList.add(value);
					sqlGenStr(columnName);
				}
			}
		}
	}
	
	/**
	 * 生成插入和更新的sql片段
	 * @param columnName
	 */
	private void sqlGenStr(String columnName) {
		if (flag) {//
			iColumnListStr.append(DalConstant.sql_pause);
			placeholderListStr.append(DalConstant.sql_pause);
			uColumnPlaceholderList.append(DalConstant.sql_pause);
			uNamedParameterListStr.append(DalConstant.sql_pause);
			iNamedParameterListStr.append(DalConstant.sql_pause);
		}
		
		iColumnListStr.append(columnName);
		placeholderListStr.append(DalConstant.sql_question);
		uColumnPlaceholderList.append(columnName).append(DalConstant.sql_eq).append(DalConstant.sql_question);
		uNamedParameterListStr.append(columnName).append(DalConstant.sql_eq).append(DalConstant.sql_colon).append(columnName);
		iNamedParameterListStr.append(DalConstant.sql_colon).append(columnName);
		
		flag = true;
	}
	
	/**
	 * 获取插入实体的字段列表sql(在组装insert字段列表)
	 * 使用范围：jdbcTemplate
	 * 形式:【col_1,col_2,col_3,...,col_n】
	 * @return the iColumnListStr
	 */
	public StringBuilder getiColumnListStr() {
		return iColumnListStr;
	}

	/**
	 * 获取插入实体字段的占位列表sql
	 * 形式:【?,?,?,...,? 】与插入列表对应
	 * @return the placeholderListStr
	 */
	public StringBuilder getPlaceholderListStr() {
		return placeholderListStr;
	}

	/**
	 * 获取更新列表sql
	 * 形式:【col_1=value1,col_2=value2,col_3=value3,...,col_n=valuen】
	 * @return the uColumnPlaceholderList
	 */
	public StringBuilder getuColumnPlaceholderList() {
		return uColumnPlaceholderList;
	}

	/**
	 * 获取插入形式的名称属性列表sql
	 * 使用范围：namedParameterJdbcTemplate
	 * 形式:【：col_1,：col_2,：col_3,...,：col_n】
	 * @return the iNamedParameterListStr
	 */
	public StringBuilder getiNamedParameterListStr() {
		return iNamedParameterListStr;
	}

	/**
	 * 获取更新形式的名称属性列表sql
	 * 使用范围：namedParameterJdbcTemplate
	 * 形式:【：col_1=value1,：col_2=value2,：col_3=value3,...,：col_n=valuen】
	 * @return the uNamedParameterListStr
	 */
	public StringBuilder getuNamedParameterListStr() {
		return uNamedParameterListStr;
	}

	public boolean hasValue(String paramName) {
		return null != getValue(paramName) ;
	}

	@Override
	public Object getValue(String paramName) throws IllegalArgumentException {
		return columnValueMap.get(paramName);
	}

	//获取解析bean时有值的属性个数
	public int getSizePropertyValue(){
		return valueList.size();
	}
	
	@Override
	public Map<String, Object> mapBean(Object object) throws SQLException {
		if (null == object) {
			logger.error("传入的对象为null。", new NullPointerException());
			throw new NullPointerException("传入的对象为null。");
		}
		this.init(object);
		return columnValueMap;
	}

	/**
	 * 读取列名对应值得map
	 * @return the columnValueMap
	 */
	public Map<String, Object> getColumnValueMap() {
		return columnValueMap;
	}

	public int getSqlType(String paramName) {
		int sqlType = super.getSqlType(paramName);
		if (sqlType != TYPE_UNKNOWN) {
			return sqlType;
		}
		Class<?> propType = this.beanWrapper.getPropertyType(paramName);
		return StatementCreatorUtils.javaTypeToSqlParameterType(propType);
	}
}
